Page Index
5 C 小程序接口访问原理、postman调试
JL 于 2020-04-26 12:15:22 +08:00 修改了此页面
此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

小程序登录

  • 先看下微信官方的文档和流程图

官方文档

登录流程时序

  • 小程序访问不走oauth2授权,所以我们要把小程序的请求自动放行,在base-weixin、base-mall的nacos配置文件中配置/api下的所有请求无需token访问,所以小程序的所有接口都要是/api/ma/xxx才能访问
## spring security 配置
security:
  oauth2:
    client:
      client-id: weixin
      client-secret: weixin
      scope: server
      # 无需token访问的url
      release-urls:
        - /api/**
  • 登录接口实现,具体逻辑请读登录接口源码/api/ma/wxuser/login,登录接口会生成一个自定义session,保存在redis中,之后的每个小程序接口都要带上这个session才能访问

小程序登录成功

  • 通过登录接口返回后会获得一个自定义session,小程序会将自定义session放入全局变量joolun-ma/app.js
api.login({
  jsCode: res.code
})
  .then(res => {
    let wxUser = res.data
    that.globalData.thirdSession = wxUser.sessionKey
    that.globalData.wxUser = wxUser
    resolve("success")
  })

小程序接口header自动赋参

  • 读joolun-ma/utils/api.js源码,可知在每次接口请求前,我们会自动给接口header中带上app-id和thirdSession登录接口返回的自定义session,所以我们自己加接口的时间无需维护tenant-id和thirdSession
wx.request({
      url: _url,
      method: method,
      data: data,
      header: {
        'app-id': wx.getAccountInfoSync().miniProgram.appId,
        'thirdSession': getApp().globalData.thirdSession
      }
 })

小程序接口新增

  • 假如要加一个商品查询接口goodsGet,在joolun-ma/utils/api.js中添加如下代码
goodsGet: (id) => {
    return request('/mall/api/ma/goodsspu/' + id, 'get', null, false)
  },
  • 其他页面就可以直接通过app.api.xx调用了
app.api.goodsGet(id)
      .then(res => {
        let goodsDetail = res.data
        this.setData({
          goodsDetail: goodsDetail
        })
      })

后台接收到接口调用后处理

  • 我们统一将非后台的相关接口放在各项目的api目录下
  • 我们以购物车接口为例joolun/base-mall/base-mall-admin/src/main/java/com/joolun/cloud/mall/admin/api/ma/ShoppingCartApi.java
 /**
 * 分页列表
 * @param page 分页对象
 * @param couponUser 电子券用户记录
 * @return
 */
@GetMapping("/page")
public R getCouponUserPage(HttpServletRequest request, Page page, CouponUser couponUser) {
    R checkThirdSession = BaseApi.checkThirdSession(couponUser, request);
    if(!checkThirdSession.isOk()) {//检验失败,直接返回失败信息
        return checkThirdSession;
    }
    return R.ok(couponUserService.page2(page, couponUser));
}
  • 每个接口都会调用BaseApi.checkThirdSession方法校验sesion并获取当前用户信息

postman调试

  • 通过上面原理介绍得知,我们只要知道thirdSession就能直接用postman调试
  • thirdSession我们可以通过微信开发者工具获取,编译一下,小程序会调用登录接口,从登录接口我们可以获取到thirdSession
  • postman调试

获取当前小程序用户的信息

  • 以购物车查询接口(/api/ma/shoppingcart/page为例 我们需要通过用户ID去获取当前用户的购物车数据,先要使用接口传过来的thirdSession去得到用户ID,调用BaseApi.checkThirdSession方法即可,此方法具有校验ThirdSession和获取当前用户的信息的功能,请自行读源码
/**
 * 校验ThirdSession,并获取当前用户的信息
 * @param baseEntity
 * @param request
 * @return
 */
public static R checkThirdSession(Model<?> baseEntity, HttpServletRequest request) {
    String thirdSession = request.getHeader("thirdSession");
    //获取缓存中的ThirdSession
    String key = WxMaConstants.THIRD_SESSION_BEGIN  + ":" + thirdSession;
    Object thirdSessionObj = redisTemplate.opsForValue().get(key);
    if(thirdSessionObj == null) {//session过期
        //返回超时错误码,触发小程序重新登录
        return R.failed(MyReturnCode.ERR_60001.getCode(), MyReturnCode.ERR_60001.getMsg());
    }else {
        String thirdSessionStr = String.valueOf(thirdSessionObj);
        ThirdSession thirdSessionData = JSONUtil.toBean(thirdSessionStr, ThirdSession.class);
        String appId_session = thirdSessionData.getAppId();
        String userId_session = thirdSessionData.getWxUserId();
        String sessionKey_session = thirdSessionData.getSessionKey();
        String openId_session = thirdSessionData.getOpenId();
        String mallUserId_session = thirdSessionData.getMallUserId();
        if (baseEntity instanceof WxUser) {
            ((WxUser) baseEntity).setAppId(appId_session);
            ((WxUser) baseEntity).setId(userId_session);
            ((WxUser) baseEntity).setSessionKey(sessionKey_session);
            ((WxUser) baseEntity).setOpenId(openId_session);
            ((WxUser) baseEntity).setMallUserId(mallUserId_session);
        }else if (baseEntity instanceof ShoppingCart){
            ((ShoppingCart) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof PlaceOrderDTO){
            ((PlaceOrderDTO) baseEntity).setUserId(mallUserId_session);
            ((PlaceOrderDTO) baseEntity).setAppId(appId_session);
        }else if (baseEntity instanceof UserAddress){
            ((UserAddress) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof OrderInfo){
            ((OrderInfo) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof UserCollect){
            ((UserCollect) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof PointsRecord){
            ((PointsRecord) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof UserInfo){
            ((UserInfo) baseEntity).setId(mallUserId_session);
        }else if (baseEntity instanceof CouponUser){
            ((CouponUser) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof BargainUser){
            ((BargainUser) baseEntity).setUserId(mallUserId_session);
        }else if (baseEntity instanceof BargainCut){
            ((BargainCut) baseEntity).setUserId(mallUserId_session);
        }
        return R.ok(baseEntity);
    }
}